package com.ddwl.common.service;


import com.ddwl.common.constant.BaseEnum;
import com.ddwl.common.constant.Constant;
import com.ddwl.common.constant.RedisKey;
import com.ddwl.common.exception.AuthException;
import com.ddwl.common.exception.ExceptionCode;
import com.ddwl.common.exception.GlobalException;
import com.ddwl.common.exception.ParamException;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author Fu Zhaohui
 */
@Component
public class AuthService {

    @Resource
    private RedisService redisService;

    public Map<String, String> auth(HttpServletRequest request) {
        String ak = request.getHeader("ak");
        String dk = request.getHeader("dk");
        String pt = request.getHeader("pt");
        String channel = request.getHeader("channel");
        if (!StringUtils.hasText(ak) || !StringUtils.hasText(dk)) {
            throw new AuthException(ExceptionCode.TOKEN_NOT_EXISTS);
        }
        BaseEnum.ProductEnum product = BaseEnum.ProductEnum.getProduct(request.getHeader("pk"));
        Map<String, String> authMap = redisService.getHashOps().entries(RedisKey.AUTH_KEY.getKey(product.getName(), ak));
//        if (!dk.equals(authMap.get("dk"))) {
//            throw new AuthException();
//        }
        if (CollectionUtils.isEmpty(authMap)) {
            throw new AuthException();
        }
        authMap.put("ak", ak);
        String userId = authMap.get("uid");
        String tokenKey = RedisKey.AUTH_KEY.getKey(product.getName(), ak);
        String authKey = RedisKey.TOKEN_KEY.getKey(product.getName(), userId);
        if (product.getApp()) {
            redisService.getHashOps().getOperations().expire(tokenKey, Constant.ACCESS_TOKEN_EXPIRE, TimeUnit.DAYS);
            redisService.getHashOps().getOperations().expire(authKey, Constant.ACCESS_TOKEN_EXPIRE, TimeUnit.DAYS);
        }
        authMap.put("pt", pt);
        authMap.put("pk", product.getName());
        authMap.put("channel", channel);
        return authMap;
    }

    public Map<String, String> preAuth(HttpServletRequest request) {
        String dk = request.getHeader("dk");
        String pt = request.getHeader("pt");
        String channel = request.getHeader("channel");
        if (!StringUtils.hasText(dk)) {
            throw new AuthException();
        }
        String ak = request.getHeader("ak");
        BaseEnum.ProductEnum product = BaseEnum.ProductEnum.getProduct(request.getHeader("pk"));
        Map<String, String> authMap = null;
        if (StringUtils.hasText(ak)) {
            authMap = redisService.getHashOps().entries(RedisKey.AUTH_KEY.getKey(product.getName(), ak));
        }
        if (authMap == null) {
            authMap = new HashMap<>(5);
        }
        authMap.put("dk", dk);
        authMap.put("pt", pt);
        authMap.put("pk", product.getName());
        if (StringUtils.hasText(channel)) {
            authMap.put("channel", channel);
        }
        return authMap;
    }

    private Map<String, String> getTokenAuth(String ip, String ak, String dk, String pk) {
        Map<String, String> authMap = redisService.getHashOps().entries(RedisKey.AUTH_KEY.getKey(pk, ak));
        if (authMap == null || authMap.size() == 0) {
            throw new AuthException(ExceptionCode.TOKEN_NOT_EXISTS);
        }
        if (!dk.equals(authMap.get("dk"))) {
            throw new AuthException();
        }
        String whitelist = authMap.get("whitelist");
        if (StringUtils.hasText(whitelist)) {
            if (!Arrays.asList(whitelist.split(",")).contains(ip)) {
                throw new GlobalException("未知服务器请求");
            }
        }
        return authMap;
    }

    public void validMobileCode(String mobile, String code) {
        String authCode = redisService.getValueOps().get(RedisKey.MOBILE_REST_SMS_KEY.getKey(mobile));
        ParamException.isTrue(!code.equals(authCode), ExceptionCode.MOBILE_AUTH_FAILED.getMsg());
    }

    /**
     * 清除用户当前平台认证
     *
     * @param product
     * @param userId
     */
    public void clearAuth(String product, String userId) {
        HashOperations<String, String, String> ops = redisService.getHashOps();
        String tokenKey = RedisKey.TOKEN_KEY.getKey(product, userId);
        String token = ops.get(tokenKey, "ak");
        String authKey = RedisKey.AUTH_KEY.getKey(product, token);
        ops.getOperations().delete(tokenKey);
        ops.getOperations().delete(authKey);
    }

    /**
     * 清除登录Token
     *
     * @param product
     * @param token
     */
    public void clearToken(String product, String token) {
        HashOperations<String, String, String> ops = redisService.getHashOps();
        String authKey = RedisKey.AUTH_KEY.getKey(product, token);
        String userId = ops.get(authKey, "uid");
        String tokenKey = RedisKey.TOKEN_KEY.getKey(product, userId);
        ops.getOperations().delete(tokenKey);
        ops.getOperations().delete(authKey);
    }

    /**
     * 清除用户所有平台登录认证Token
     *
     * @param userId
     */
    public void clearUserToken(String userId) {
        HashOperations<String, String, String> ops = redisService.getHashOps();
        String tokenKey = RedisKey.TOKEN_KEY.getKey("*", userId);
        Set<String> keys = ops.keys(tokenKey);
        keys.forEach(key -> {
            String token = ops.get(key, "ak");
            String product = ops.get(key, "pk");
            String authKey = RedisKey.AUTH_KEY.getKey(product, token);
            ops.getOperations().delete(key);
            ops.getOperations().delete(authKey);
        });
    }

    public void mergeAuth(String product, String fromUserId, String toUserId) {
        String authKey = RedisKey.TOKEN_KEY.getKey(product, fromUserId);
        HashOperations<String, String, String> hashOps = redisService.getHashOps();
        String ak = hashOps.get(authKey, "ak");
        if (!StringUtils.hasText(ak)) {
            return;
        }
        String tokenKey = RedisKey.AUTH_KEY.getKey(product, ak);
        hashOps.getOperations().delete(authKey);
        hashOps.put(tokenKey, "uid", toUserId);
        authKey = RedisKey.TOKEN_KEY.getKey(product, toUserId);
        hashOps.put(authKey, "ak", ak);
    }

}
